/**
 * 
 * Copyright (C) 2011 Cody Stoutenburg . All rights reserved.
 *
 *       This program is free software; you can redistribute it and/or
 *       modify it under the terms of the GNU Lesser General Public License
 *       as published by the Free Software Foundation; either version 2.1
 *       of the License, or (at your option) any later version.
 *
 *       This program is distributed in the hope that it will be useful,
 *       but WITHOUT ANY WARRANTY; without even the implied warranty of
 *       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *       GNU Lesser General Public License for more details.
 *
 *       You should have received a copy of the GNU Lesser General Public License
 *       along with this program; if not, write to the Free Software
 *       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. 
 * 
 */
package ca.usherbrooke.view.slick.jade.worldView.shared;

import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.List;

import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.geom.Circle;
import org.newdawn.slick.geom.Line;

import ca.usherbrooke.tools.position.Vector2D;

/**
 * this class allow the developer to print different info on the map<br/>
 * this class is not synchronized so it may have some synchronization error but
 * it's not really important because it's only for debug purpose and the draw
 * method take in account the possibility of
 * <code>ConcurrentModificationException</code>
 * 
 * @author Cody Stoutenburg
 * 
 */
public class EntityViewDebug {
	public static final EntityViewDebug INSTANCE = new EntityViewDebug();

	private class EntityInfo<E> {
		private final HashMap<Long, ArrayList<E>> allInfo;

		public EntityInfo() {
			allInfo = new HashMap<Long, ArrayList<E>>();
		}

		public ArrayList<E> getAllValue(Long entity) {
			ArrayList<E> allPos = allInfo.get(entity);
			if (allPos == null) {
				allInfo.put(entity, new ArrayList<E>());
				allPos = allInfo.get(entity);
			}
			return allPos;
		}

		public void addInfo(Long entity, E position) {
			getAllValue(entity).add(position);
		}

		public void addInfo(Long entity, List<E> position) {
			getAllValue(entity).addAll(position);
		}

		public void clearInfo(Long entity) {
			getAllValue(entity).clear();
		}
	}

	private final HashMap<Long, Vector2D> targetDestination;
	private final EntityInfo<Vector2D> allPosition;
	private final EntityInfo<Vector2D> allWalls;
	private final EntityInfo<Vector2D> allRoad;

	public EntityViewDebug() {
		super();
		targetDestination = new HashMap<Long, Vector2D>();
		allPosition = new EntityInfo<Vector2D>();
		allWalls = new EntityInfo<Vector2D>();
		allRoad = new EntityInfo<Vector2D>();
	}

	/**
	 * set the target position to print in debug. <br/>
	 * it will be draw in green
	 * 
	 * @param entity
	 * @param position
	 */
	public void setTargetPosition(Long entity, Vector2D position) {
		targetDestination.put(entity, position);
	}

	/**
	 * set the position to print in debug. <br/>
	 * it will be draw in red
	 * 
	 * @param entity
	 * @param position
	 */
	public void addPosition(Long entity, Vector2D position) {
		allPosition.addInfo(entity, position);
	}

	/**
	 * set the position to print in debug. <br/>
	 * it will be draw in red
	 * 
	 * @param entity
	 * @param position
	 */
	public void addPosition(Long entity, List<Vector2D> position) {
		allPosition.addInfo(entity, position);
	}

	/**
	 * remove all position that are draw in red
	 * 
	 * @param entity
	 */
	public void clearPosition(Long entity) {
		allPosition.clearInfo(entity);
	}

	/**
	 * get all points that are draw in red
	 * 
	 * @param entity
	 * @return all points that are draw in red
	 */
	public ArrayList<Vector2D> getAllPosition(Long entity) {
		return allPosition.getAllValue(entity);
	}

	/**
	 * set the position to draw in grey
	 * 
	 * @param entity
	 * @param position
	 */
	public void addWall(Long entity, Vector2D position) {
		allWalls.addInfo(entity, position);
	}

	/**
	 * set the position to draw in grey
	 * 
	 * @param entity
	 * @param position
	 */
	public void addWall(Long entity, List<Vector2D> position) {
		allWalls.addInfo(entity, position);
	}

	/**
	 * remove all points that are draw in grey
	 * 
	 * @param entity
	 */
	public void clearWalls(Long entity) {
		allWalls.clearInfo(entity);
	}

	/**
	 * get all points that are draw in grey
	 * 
	 * @param entity
	 * @return all points that are draw in grey
	 */
	public ArrayList<Vector2D> getAllWalls(Long entity) {
		return allWalls.getAllValue(entity);
	}

	/**
	 * draw lines between points in the order they are added
	 * 
	 * @param entity
	 * @param position
	 */
	public void addRoad(Long entity, Vector2D position) {
		allRoad.addInfo(entity, position);
	}

	/**
	 * draw lines between points
	 * 
	 * @param entity
	 * @param position
	 */
	public void addRoad(Long entity, List<Vector2D> position) {
		allRoad.addInfo(entity, position);
	}

	/**
	 * remove all points that draw lines
	 * 
	 * @param entity
	 */
	public void clearRoad(Long entity) {
		allRoad.clearInfo(entity);
	}

	public ArrayList<Vector2D> getAllRoads(Long entity) {
		return allRoad.getAllValue(entity);
	}

	/**
	 * the methods that render the debug info
	 * 
	 * @param entity
	 * @param g
	 */
	public void render(Long entity, Graphics g) {
		try {
			Color orgColor = g.getColor();
			// all debug info are in red
			g.setColor(Color.red);

			ArrayList<Vector2D> allPos = getAllPosition(entity);
			for (Vector2D position : allPos) {
				g.draw(new Circle(position.getX().floatValue(), position.getY()
						.floatValue(), 2));
			}

			ArrayList<Vector2D> allRoads = getAllRoads(entity);
			if (allRoads.size() > 1) {
				Vector2D previous = allRoads.get(0);
				for (int i = 1; i < allRoads.size(); ++i) {
					Vector2D current = allRoads.get(i);
					Line l = new Line(current.getX().floatValue(), current
							.getY().floatValue(), previous.getX().floatValue(),
							previous.getY().floatValue());
					previous = current;
					g.draw(l);
				}
			}

			g.setColor(Color.gray);
			ArrayList<Vector2D> allWalls = getAllWalls(entity);
			for (Vector2D position : allWalls) {
				g.draw(new Circle(position.getX().floatValue(), position.getY()
						.floatValue(), 2));
			}

			g.setColor(Color.green);
			Vector2D target = targetDestination.get(entity);
			if (target != null) {
				g.draw(new Circle(target.getX().floatValue(), target.getY()
						.floatValue(), 2));
			}
			g.setColor(orgColor);
		} catch (ConcurrentModificationException ex) {
			// here we could have a concurent modification exception but we
			// don't care if we cannot print this time we will print it later
			// synchronization is too slow so we accept to not update every time
			// the debug info
			// System.out.println("do not update debug view");
		}
	}
}
